package IDGeneratorTools

import (
	"errors"
	"strconv"
	"time"
	"frame/utils/DateFormatUtils"
	"math/rand"
)

/**
掩码制造，从0开始，包含start，包含end，start>=0，end<=63
 */
func CreateMask(start uint64 ,end uint64 )(uint64,error){
	if(start <0 || start >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=start<=63 ")
	}
	if(end <0 || end >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=end<=63 ")
	}
	if(end <start ) {
		return 0,errors.New("IDGeneratorTools createMask must: end >= start ")
	}
	var result uint64 = 0xffffffffffffffff;
	result = result << (64-(end+1-start));
	result = result >> start;	//int型右移，高位补符号位。uint型右移，高位补0
	return result,nil;
}

/**
给old代表的64位数字中的第start到第end位，设置一个数字为val，如果val超出start和end的长度区间，则舍弃掉超出的内容
 */
func SetValue(old uint64, val uint64, start uint64, end uint64)(uint64,error){
	if(start <0 || start >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=start<=63 ")
	}
	if(end <0 || end >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=end<=63 ")
	}
	if(end <start ) {
		return 0,errors.New("IDGeneratorTools createMask must: end >= start ")
	}
	var result uint64 = old;
	var mask ,_ = CreateMask(start,end);
	result = result & (0xffffffffffffffff ^ mask);//result与掩码的反码进行与操作，将指定位置为0
	var value uint64 = val;
	value = value << (64-(end+1-start));        //左移到指定位置
	value = value >>  start;					 //int型右移，高位补符号位。uint型右移，高位补0
	value = value & mask;                       //与掩码进行计算
	result = result | value;                    //将原值与新值进行组合
	return result,nil;
}


/**
获取到 l 中的第start到end位的数据并转换为uint64
 */
func GetValue(l uint64,start uint64,end uint64)(uint64,error){
	if(start <0 || start >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=start<=63 ")
	}
	if(end <0 || end >63 ) {
		return 0,errors.New("IDGeneratorTools createMask must: 0<=end<=63 ")
	}
	if(end <start ) {
		return 0,errors.New("IDGeneratorTools createMask must: end >= start ")
	}
	return (((l<<start)>>1&0xffffffffffffffff)>>(start-1)>>(63-end)),nil
}

/**
打印l 的从0开始第index位的数据
 */
func pl(l uint64,index uint64)(string){
	return strconv.Itoa(int(0x0000000000000001 & (l>> (63-index))));
}

/**
打印一个long的二进制码,split指是否分割为4位一组
 */
func pl64(l uint64, split bool)(string) {
	var sb= make([]byte, 0, 10)
	for i := 0; i < 64; i++ {
		sb = append(sb, []byte(pl(l, uint64(i)))...)
		if ((i+1)%4 == 0 && split) {
			sb = append(sb, []byte(" ")...)
		}
	}
	sb = append(sb, []byte("\r\n")...)
	return string(sb)
}

/**
ji's计时起始秒数
 */
var datetimestart = time.Date(2018,4,20,0,0,0,0,time.Local).Unix()

/**
创建一个简单的uint64,number 要储存的数据，可以是0-33554430闭区间内的数字
 */
func CreateSimpleUint64ByNumber(number uint64)(uint64,error){
	if(number<0||0>33554431){
		return 0,errors.New("CreateSimpleLong储存的number可以是[0-33554431]闭区间内的数字")
	}
	var origin uint64 = 0;
	var d = time.Now().Unix() //距离20060102150405的秒数
	d = d - datetimestart	//缩减空间设置起始时间为2018-4-20
	var pk,_ = SetValue(origin,uint64(d),1,38)//0为正负号，1到38位为毫秒时间，可以储存2^38毫秒，使用8.7年
	pk,_ = SetValue(pk,number,39,63)//设置39到63位为number，可储存2^25-1,即33554431以内的数字
	return pk,nil
}

func CreateSimpleUint64()(uint64,error){
	return CreateSimpleUint64ByNumber(uint64(rand.Int()%33554431))
}

/**
从一个uint64中获取时间
 */
func GetDateTimeFromLong(l uint64)(string,error){
	var diffTime,_ = GetValue(l,1,38);
	var tm = uint64(datetimestart)+diffTime;
	var t = time.Unix(int64(tm),0)
	return t.Format("20060102150405"),nil
}
/**
 *  生成标准id
 * @param country    国家编号，范围0-3
 * @param city      城市编号，范围0-7
 * @param l1center  一级计算中心，范围0-3
 * @param l2center  二级计算中心，范围0-63
 * @param number    随机数，范围0-4095
 */
func CreateStandardLong(country uint64, city uint64, l1center uint64, l2center uint64, number uint64)(uint64,error) {
	var origin uint64 = 0;
	var d = time.Now().Unix() //距离20060102150405的秒数
	d = d - datetimestart	//缩减空间设置起始时间为2018-4-20
	var pk,_ = SetValue(origin,uint64(d),1,38);//0为正负号，1到38位为毫秒时间，可以储存2^38毫秒，使用8.7年
	pk,_ = SetValue(pk, country, 39, 40);//设置39到40位为国家，可储存2^2-1,即0-3以内的数字，四个国家
	pk,_ = SetValue(pk, city, 41, 43);//设置41到43位为城市，可储存2^3-1,即0-7以内的数字，八个城市
	pk,_ = SetValue(pk, l1center, 44, 45);//设置44到45位为一级计算中心，可储存2^2-1,即0-3以内的数字，四个一级计算中心
	pk,_ = SetValue(pk, l2center, 46, 51);//设置46到49位为二级计算中心，可储存2^6-1,即0-63以内的数字，六十四个二级计算中心
	pk,_ = SetValue(pk, number, 52, 63);//设置52到63位为随机数，可储存2^12-1,即0-4095以内的数字，支持1毫秒4096的并发
	return pk,nil
}

func ParseStandardLong(pk uint64)([]interface{}){
	var result = make([]interface{},6)
	var diffTime,_ = GetValue(pk,1,38);
	result[0] = time.Unix(datetimestart+int64(diffTime),0).Format(DateFormatUtils.DATEFORMAT_yyyyMMddHHmmss);
	result[1],_ = GetValue(pk,39,40);
	result[2],_ = GetValue(pk,41,43);
	result[3],_ = GetValue(pk,44,45);
	result[4],_ = GetValue(pk,46,51);
	result[5],_ = GetValue(pk,52,63);
	return result;
}